#include "types.h"
#include "stat.h"
#include "user.h"
#include "fcntl.h"

/***

Test 2 – I/O test
After passing the sanity test, the I/O test will provide a more complex test. Add a
program named fibonacci. The arguments to this user space program is an integer value
denoted by   (use command line arguments. e.g., $ fibonacci 30). This value
represents an index in the Fibonacci sequence (A000045 in OEIS). The program then
forks 30 child processes, each with its id (from 0 to 29) denoted by    . Each process is responsible to calculate the sequence's

element. An even process iteratively
calculates each element from the first until the

, and in each iteration writes the
current element and the previous element to a file named ‘FibTest<   >.txt’ and prints it
to the standard output ‘FibTest<cid> <current>,<previous>’. At the beginning of each
iteration, the process reads the data from the file and calculates the next element. An
odd process uses local variables to do the same computation (it will not use a file or
print to standard output).
Once the answer is calculated by a process (even or odd) a message is displayed:
FibTest: proc <cid> finished its calculation
The parent process will output the same statistics as in the sanity test.
 ****/

#define PROC_COUNT 30
#define FILENAME_LENGTH 14
#define MAX_STR_LEN 32

void
panic(char *s)
{
  printf(2, "%s\n", s);
  exit();
}

void evenTask(int cid, int num){
	int fd,i;
	int fib0, fib1;
	char filename[FILENAME_LENGTH] = "FibTest00.txt";
	char * strf1;
	char * strf2;

	fib0 = 0;
	fib1 = 1;

	filename[7] = (char)('0' + (cid / 10));
	filename[8] = (char)('0' + (cid % 10));

	if((fd = open(filename, (O_WRONLY | O_CREATE))) < 0){
		printf(1, "cat: cannot open %s\n", filename);
		exit();
	}

	printf(fd, "%d\n", fib0);
	printf(fd, "%d\n", fib1);
	close(fd);


	strf1 = malloc(MAX_STR_LEN);
	strf2 = malloc(MAX_STR_LEN);
	for (i = 0; i < num; ++i) {
		if((fd = open(filename, O_RDWR)) < 0){
			printf(1, "cat: cannot open %s\n", filename);
			exit();
		}
		getsfd(strf1, MAX_STR_LEN, fd);
		strf1[strlen(strf1)-1] = '\0'; // Chop '\n'
		getsfd(strf2, MAX_STR_LEN, fd);
		strf2[strlen(strf2)-1] = '\0'; // Chop '\n'
		close(fd); // close before overwriting the file

		if((fd = open(filename, O_RDWR)) < 0){
			printf(1, "cat: cannot open %s\n", filename);
			exit();
		}
		fib0 = atoi(strf1);
		fib1 = atoi(strf2);
		printf(1, "FibTest%d %d, %d\n", cid, fib1, fib0);
		printf(fd, "%d\n", fib1);
		printf(fd, "%d\n", fib0+fib1);
		close(fd);

	}

	free(strf1);
	free(strf2);
	printf(1, "FibTest: proc %d finished its calculation\n", cid);
	exit();

}

void oddTask(int cid, int num){
	int fib0,fib1,i,next;

	fib0 = 0;
	fib1 = 1;

	for (i = 0; i < num; ++i) {
		next = fib0+fib1;
		fib0 = fib1;
		fib1 = next;
	}
	printf(1, "FibTest: proc %d finished its calculation\n", cid);
	exit();
}


int
main(int argc, char *argv[])
{


	int i;
	int cids[PROC_COUNT];
	int wtime[PROC_COUNT];
	int rtime[PROC_COUNT];
	int father;
	int avrgW;
	int avrgT;
	int avrgR;
	int num;

	avrgW = 0;
	avrgT = 0;
	avrgR = 0;

	father = getpid();
	if (argc > 1)
		num = atoi(argv[1]);
	else{
		printf(2, "usage: $./fibonacci 30 (for 30'th element)\n");
		exit();
	}



	for(i=0; i<PROC_COUNT; ++i){
		if ((cids[i] = fork()) == 0){
			if (i % 2)
				oddTask(i, num);
			else
				evenTask(i, num);
		}
	}

	if (getpid() != father)
		panic("child escaped!");
	else {
		//father section
		for (i = 0; i < PROC_COUNT; ++i) {
			if (wait2(&wtime[i],&rtime[i]) <0){
				printf(2, "fibonacci error on wait2\n");
				exit();
			}
		}
		for (i = 0; i < PROC_COUNT; ++i) {
			avrgW += wtime[i];
			avrgR += rtime[i];
		}
		avrgW = (avrgW)/PROC_COUNT;
		avrgR = (avrgR)/PROC_COUNT;
		avrgT = (avrgW + avrgR);

		printf(1, "Average waiting: %d, ", avrgW);
		printf(1, "running: %d, ", avrgR);
		printf(1, "turnaround: %d\n", avrgT);

		for (i = 0; i < PROC_COUNT; ++i) {
			printf(1, "cid %d, wtime=%d, rtime=%d, ttime%d\n", i, wtime[i], rtime[i], wtime[i]+rtime[i]);
		}

	}

	exit();

}
